package pms.dao;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;

import java.util.Set;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import pms.om.Abwesenheitsart;
import pms.om.Feiertag;
import pms.om.Mitarbeiter;
import pms.om.MitarbeiterAbwesend; 
import pms.om.Sperrtag;
import pms.om.Abteilung;

/**
 * @author Steffi
 *
 */
public class MitarbeiterAbwesendDao extends HibernateDaoSupport {
	
	/** &Uuml;berpr&uuml;fe folgendes bei einer Abwesenheit: 
	 *  ist das Jahr des Datums datumstart gleich dem Jahr des datumende?
	 *  Wenn ja, dann wird true zur&uuml;ckgeben, ansonsten false
	 * @param datumstart
	 * @param datumende
	 */ 
 
	public boolean beginnUndEndeAbwesenheitImGleichenJahr(Date datumstart, Date datumende) {
		boolean result = false;
		Calendar cal_1 = new GregorianCalendar();
		Calendar cal_2 = new GregorianCalendar();
		cal_1.setTime(datumstart);
		int jahr1 = cal_1.get(Calendar.YEAR); 
		cal_2.setTime(datumende);    
		int jahr2 = cal_2.get(Calendar.YEAR);
		if (jahr1 == jahr2) {
			result = true;
		} else {
			result = false;
		}		
		return result;
	}
	
   /** bei einer Abwesenheit: ist das Enddatum gr&ouml;ßer als das Startdatum der Abwesenheit ?
	 * wenn ja, dann wird true zur&uuml;ckgeben, ansonsten false
	 * @param datumstart
	 * @param datumende
	 */
	
	public boolean datumEndeGroesseroderGleichDatumStart(Date datumstart, Date datumende) {
		if (datumende.compareTo(datumstart) >= 0) {
			return true;
		} else {
			return false;
		}
	}
	
	/** gibt das Jahr als Integer zur&uuml;ck: &Uuml;bergabe der id der Abwesenheit eines Mitarbeiters.
	  * Ist z.B. der Mitarbeiter vom 01.01.2012 bis 10.01.2012 weg, so wird 2012 zur&uuml;ckgegeben	 
	  * @param id
	  * @return jahr
	  */
	
	public int fuerWelchesJahr(int id) {
		HibernateTemplate template = getHibernateTemplate();
		MitarbeiterAbwesend ma = (MitarbeiterAbwesend) template.get(MitarbeiterAbwesend.class, id);	
		Calendar cal = new GregorianCalendar();
		cal.setTime(ma.getVonDatum());		
		int jahr = cal.get(Calendar.YEAR); 
		return jahr;
	}
	
	
	/** gibt das Jahr als Integer zur&uuml;ck: &Uuml;bergabe der id der Abwesenheit eines Mitarbeiters.
	  * Ist z.B. der Mitarbeiter vom 01.01.2012 bis 10.01.2012 weg, so wird 2012 zur&uuml;ckgegeben	
 	  * @param ma
	  * @return jahr
	  */
	
	public int fuerWelchesJahr(MitarbeiterAbwesend ma) {
		Calendar cal = new GregorianCalendar();
		cal.setTime(ma.getVonDatum());		
		int jahr = cal.get(Calendar.YEAR); 
		return jahr;
	}
	 
	/** R&uml;ckgabe einer Abwesenheit anhand der id
 	  * @param id
	  */

	public MitarbeiterAbwesend findById(int id) {
		HibernateTemplate template = getHibernateTemplate();
		return (MitarbeiterAbwesend) template.get(MitarbeiterAbwesend.class, id);
	}

	/**
	 * erzeuge die Abwesenheit für Mitarbeiter mit der id = idm
	 * ida ist die id der Abwesenheitsart und datumstart bis datumende der Zeitraum
	 * @param idm
	 * @param ida
	 * @param datumstart
	 * @param datumende
	 */
	
	public void createVorgemerkteAbwesenheit(int idm, int ida, Date datumstart, Date datumende) {
		HibernateTemplate template = getHibernateTemplate();
		Mitarbeiter m = (Mitarbeiter) template.get(Mitarbeiter.class, idm);
		Abwesenheitsart a = (Abwesenheitsart) template.get(Abwesenheitsart.class, ida);
		MitarbeiterAbwesend ma = new MitarbeiterAbwesend(m, a, datumstart, datumende);
		template.save(ma);
		template.flush();
	}
	
	/**
	 * l&ouml;sche eine Abwesenheit, die mit Prim&auml;rschlüssel id abgespeichert ist 
	 * @param id
	 */
	
	public boolean deleteVorgemerkteAbwesenheit(int id) {
		HibernateTemplate template = getHibernateTemplate();
		MitarbeiterAbwesend ma = (MitarbeiterAbwesend) template.get(MitarbeiterAbwesend.class, id);
		template.delete(ma);
		template.flush();
		// Kann gelöcht werden da keine Abhängigkeiten
		return true;
	}
	
	/**
	 * errechne die Anzahl der Tage als int: &Uuml;bergabe ist die Abwesenheit ma
	 * @param ma
	 * @param feiertage
	 * @param sperrtage
	 * @return
	 */
	
	public int tage(MitarbeiterAbwesend ma, Set<Feiertag> feiertage, Set<Sperrtag> sperrtage) {
		Calendar cal_1 = new GregorianCalendar();
		Calendar cal_2 = new GregorianCalendar();
		cal_1.setTime(ma.getVonDatum());
		cal_2.setTime(ma.getBisDatum());    
		long Zeit = cal_2.getTime().getTime() - cal_1.getTime().getTime();  
		long Tage = Math.round( (double)Zeit / (24. * 60.*60.*1000.)) + 1;
		int tage = (int)Tage;
		// Abgleich ob Sperrtage = Feiertag dann bei Feiertagen abziehen
		// z.B. wenn Samstag Sperrtag ist, und der Samstag ist ein Feiertag, dann bei Feiertagen nicht 
		// berücksichtigen
		Set<Date> feiertagekorrigiert = new HashSet<Date>();
		Calendar tempcal = new GregorianCalendar();
		int temptag;
		for (Feiertag feiertag : feiertage) {
			tempcal.setTime(feiertag.getFeiertagsdatum());
			for (Sperrtag wochentag : sperrtage) {
				temptag = Integer.parseInt(wochentag.getSperrtagname());
				if (tempcal.get(Calendar.DAY_OF_WEEK) == temptag) {
				} else { 
					feiertagekorrigiert.add(feiertag.getFeiertagsdatum());
				} 
			}
		}
		// wenn Feiertag in die Abwesenheit fällt, dann abziehen
		for (Date date : feiertagekorrigiert) {
			if (  ( date.compareTo(ma.getVonDatum()) > 0 ) && ( date.compareTo(ma.getBisDatum()) <= 0 ) ) {
			tage--;
			}
		}	
		// wenn Sperrtag in die Abwesenheit fällt, dann abziehen
		Calendar tempcal2 = new GregorianCalendar();
		Iterator<Date> idatum = new DatumsIterator(ma.getVonDatum(), ma.getBisDatum());
		while (idatum.hasNext()) {
			tempcal2.setTime(idatum.next());
			for (Sperrtag wochentag : sperrtage) {
				temptag = Integer.parseInt(wochentag.getSperrtagname());
				if (tempcal2.get(Calendar.DAY_OF_WEEK) == temptag) {
					tage--;
				}
			}
		}
		return tage;
	}

	/**
	 * gebe die Anzahl der Tage als int zur&uuml;ck
	 * &Uuml;bergabe ist die Abwesenheit mit Prim&auml;rschlüssel id und die Feiertage und 
	 * Sperrtage des betreffenden Jahres
	 * @param id
	 * @param feiertage
	 * @param sperrtage
	 * @return
	 */
	
	public int fuerGenehmigungAnzahlTage(int id, Set<Feiertag> feiertage, Set<Sperrtag> sperrtage) {
		HibernateTemplate template = getHibernateTemplate();
		MitarbeiterAbwesend ma = (MitarbeiterAbwesend) template.get(MitarbeiterAbwesend.class, id);	
		// Wieviel Tage braucht der Mitarbeiter noch in diesem Jahr für die Abwesenheit unter der Berücksichtigung 
		// von Feiertagen und Sperrtagen ?
		return (tage(ma, feiertage, sperrtage));

	}	
	
	/**
	 * gebe die Anzahl der Tage als int zur&uuml;ck
	 * &Uuml;bergabe ist die Abwesenheit mit Prim&auml;rschlüssel id und die Feiertage und 
	 * Sperrtage des betreffenden Jahres
	 * @param id
	 * @param feiertage
	 * @param sperrtage
	 */
	
	public int bereitsGenehmigungAnzahlTage(int id, Set<Feiertag> feiertage, Set<Sperrtag> sperrtage) {
		HibernateTemplate template = getHibernateTemplate();
		MitarbeiterAbwesend ma = (MitarbeiterAbwesend) template.get(MitarbeiterAbwesend.class, id);	
		// aktuell gefragtes Jahr 
		int aktjahr = fuerWelchesJahr(ma);
		// Wieviel Tage hat er in diesem Jahr schon genehmigt bekommen
		Mitarbeiter m = ma.getMitarbeiterabwesend();
		// alle Abwesenheiten des Mitarbeiters insgesamt
		Set<MitarbeiterAbwesend> alleabwesenheiten = m.getAbwesenheitendesmitarbeiters();
		// zunächst keine genehmigten Tage
		int schongenehmigt = 0;
		// nun alle Abwesenheiten durchlaufen
		for (MitarbeiterAbwesend maschleife : alleabwesenheiten) {
			// ist die Abwesenheit im aktuell abgefragten Jahr und ist die durchlaufene Abwesenheit
			// eine genehmigte Abwesenheit, dann addiere zu schongenehmigt die Anzahl der errechneten Tage zu:
			// dazu die Methode tage(...) aufrufen.
			if ((maschleife.getStatus()).equals("genehmigt") && (fuerWelchesJahr(maschleife) == aktjahr)) {
				schongenehmigt = schongenehmigt + tage(maschleife, feiertage, sperrtage); 
			}
		}
		return schongenehmigt;
	}
	
	/**
	 * &uuml;berpr&uuml;fen, ob alle g&uuml;ltigen Datums sind
	 * @param ds
	 * @param de
	 */
	
	public boolean pruefedatum(String ds, String de) {
		boolean result = false;
		DatumPruefer d = new DatumPruefer();
		try {
			if (d.datumOK(ds)) {result = true;} else {result = false;}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			if (d.datumOK(de)) {result = true;} else {result = false;}
		} catch (Exception e) {
			e.printStackTrace();
		}		
		return result;
	}

	/**
	 * &auml;ndere nur den Status auf genehmigt
	 * @param ida
	 */
	
	public void aendereStatusderAbwesenheit(int ida) {
		HibernateTemplate template = getHibernateTemplate();
		MitarbeiterAbwesend ma = findById(ida);
		ma.setStatus("genehmigt");
		template.saveOrUpdate(ma);
		template.flush();
	}

	/**
	 * Alle Abwesenheiten aus dem Set l&ouml;schen
	 * @param gibAbwesenheitendienichtgenehmigtfuerMitarbeiterimJahr
	 */
	
	public void deleteAbwesenheiten(Set<MitarbeiterAbwesend> gibAbwesenheitendienichtgenehmigtfuerMitarbeiterimJahr) {
		for (MitarbeiterAbwesend mitarbeiterAbwesend : gibAbwesenheitendienichtgenehmigtfuerMitarbeiterimJahr) {
			deleteVorgemerkteAbwesenheit(mitarbeiterAbwesend.getId());
		}
	}

	/**
	 * &Uuml;berlappen sich Abwesenheiten des Mitarbeiters?
	 * wenn true zur&uuml;ck gegeben wird, dann keine &Uuml;berlappung!
	 * @param idm
	 * @param von1
	 * @param bis1
	 */
	
	public boolean nichtueberlappendeAbwesenheiten(int idm, Date von1, Date bis1) {
		HibernateTemplate template = getHibernateTemplate();
		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");
		Mitarbeiter m = (Mitarbeiter) template.get(Mitarbeiter.class, idm);
		Set<MitarbeiterAbwesend> mset = m.getAbwesenheitendesmitarbeiters();
		boolean result = true;  // zunächst alles ok ??
		df.format(von1);
		df.format(bis1);
		for (MitarbeiterAbwesend ma : mset) {
				Date von2 = ma.getVonDatum();
				Date bis2 = ma.getBisDatum();
				df.format(von2);
				df.format(bis2);
				if ( (bis1.before(von2)) || (bis2.before(von1))) {	
					result = true;
				} else {
					result = false;
					break;
				}
		}
		return result;
	}
	
	/**
	 * Pr&uuml;fung, in welchen Abteilungen sitzt Mitarbeiter mit id = idm.
	 * Haben andere Mitarbeiter in den betreffenden Abteilungen im 
	 * Abwesenheitszeitraum mit der id = ida ebenfalls schon genehmigte Tage und 
	 * ist die Anzahl, der in der Abteilung maximal frei habenden Mitarbeiter 
	 * &uuml;berschritten, dann kann nicht genehmigt werden ---> R&uuml;ckgabe: false
	 * @param idm
	 * @param ida
	 */
	
	public boolean pruefeobAbhaengigkeitzuanderenAbteilungen(int idm, int ida) {
		boolean result = true;   //  zunächst true
		boolean innerresult = true; // zunächst true
		int anzahlzuzaehlen = 0;
		HibernateTemplate template = getHibernateTemplate();
		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");
		Mitarbeiter m = (Mitarbeiter) template.get(Mitarbeiter.class, idm);
		MitarbeiterAbwesend zupruefendeAbwesenheit = findById(ida);
		Date zupruefendvondatum = zupruefendeAbwesenheit.getVonDatum(); 
		Date zupruefendbisdatum = zupruefendeAbwesenheit.getBisDatum();
		df.format(zupruefendvondatum);
		df.format(zupruefendbisdatum);
		// System.out.println(zupruefendvondatum);  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
		// System.out.println(zupruefendbisdatum);  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
		//
		Set<Abteilung> setabteilungenindenenmitarbeiterbeschaeftigt = m.getAbteilungendesmitarbeiters();
		// nur in die inneren Schleifen, wenn der Mitarbeiter überhaupt in einer oder mehreren Abteilungen ist	
		if (!(setabteilungenindenenmitarbeiterbeschaeftigt.isEmpty())) {
			// 1. Schleife: alle Abteilungen durchgehen
			for (Abteilung abteilung : setabteilungenindenenmitarbeiterbeschaeftigt) {
				//
				int aktanzahlduerfenfehlen = Integer.parseInt(abteilung.getMaximal_duerfen_gleichzeitig_fehlen());
				//
				if (aktanzahlduerfenfehlen > 0) {   // nur wenn überhaupt > 0 dann in die inneren Schleifen
					// System.out.println("BEGINN");  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX					// System.out.println("Abteilung:" + abteilung.getAbteilungsname());  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
					Set<Mitarbeiter> mitarbeiterset = abteilung.getMitarbeiterinabteilung();
					// System.out.println("aktanzahlduerfenfehlen: " + aktanzahlduerfenfehlen);  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
					anzahlzuzaehlen = 0;
					// 2. Schleife: alle Mitarbeiter der entsprechenden Abteilungen aus der 1. Schleife durchgehen
					for (Mitarbeiter mm : mitarbeiterset) {
						// System.out.println(mm.getNachname()); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
						//
						// nur in die 3. Schleife wenn nicht Mitarbeiter selbst !
						if (!(mm.equals(m))) {
							Set<MitarbeiterAbwesend> abwesenheitenset = mm.getAbwesenheitendesmitarbeiters();
							// 3. Schleife: alle Abwesenheiten des Mitarbeiters aus der 2. Schleife durchgehen
							innerresult = true;  // zunächst auf true  
							for (MitarbeiterAbwesend abw : abwesenheitenset) {
								//
								// System.out.println(mm.getNachname() + " " + abw.getVonDatum() + " " + abw.getBisDatum()); // XXXXXXXXXXX
								//
								// Pruefung ob gerade ueberpruefte Abwesenheit genehmigt!
								if ((abw.getStatus()).equals("genehmigt")) {
									Date aktvon = abw.getVonDatum();
									Date aktbis = abw.getBisDatum();
									// pruefe Datums
									if ( (zupruefendbisdatum.before(aktvon)) || (aktbis.before(zupruefendvondatum))) {	
										innerresult = true;
										// System.out.println("           true");     // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
									} else {
										innerresult = false;	
										// System.out.println("           false");    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
										break;
									}
								}
							}	 
							// Ende 3. Schleife
							if (!innerresult) {
								anzahlzuzaehlen++;
							}						
							}
						}
						// System.out.println("innerresult: " + innerresult + "   anzahlzuzaehlen: " + anzahlzuzaehlen);	// XXXXXXXXXXX
					}
					// Ende 2. Schleife
					if (aktanzahlduerfenfehlen > anzahlzuzaehlen) {
						result = true;
					} else {
						result = false;
						break;
					}
					// System.out.println("ENDERGEBNIS: " + result);  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
			}
			// Ende 1. Schleife	
		}	
		return result;
	}	

}